// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved.
 * Description: dfx proc ops
 * Author: Huawei Technologies Co., Ltd
 * Create: 2023-06-12
 */

#ifndef __DFX_PROC_OPS_H
#define __DFX_PROC_OPS_H
#include <linux/sched.h>
#include <linux/perf_schedtime.h>
#include <linux/task_struct_extend.h>
#ifdef CONFIG_EULEROS_DFX_PERF_SCHED_TOOLS
#define PROC_NUMBUF_ULONG 21
#define DEFINE_EXTRA_PROC_UL_OPS(name)						\
static ssize_t proc_##name##_read(struct file *file, char __user *buf,		\
		size_t count, loff_t *ppos)					\
{										\
	struct task_struct *task = get_proc_task(file_inode(file));		\
	struct vendor_task *extra_task;					\
	char buffer[PROC_NUMBUF_ULONG];						\
	size_t len;								\
	int ret;								\
										\
	if (!task)								\
		return -ESRCH;							\
										\
	extra_task = task_to_vendor_task(task);					\
	if (extra_task) {							\
		len = snprintf(buffer, sizeof(buffer), "%lu\n", 		\
				extra_task->name);				\
		ret = simple_read_from_buffer(buf, count, ppos, buffer, len);	\
	}									\
										\
	put_task_struct(task);							\
	return ret;								\
}										\
										\
static ssize_t proc_##name##_write(struct file *file,				\
		const char __user *buf,						\
		size_t count,							\
		loff_t *ppos)							\
{										\
	struct task_struct *task;						\
	struct vendor_task *extra_task;						\
	struct task_struct *thread;						\
        struct vendor_task *extra_thread;					\
	unsigned long val;							\
	int ret;								\
										\
	ret = kstrtoul_from_user(buf, count, 0, &val);				\
	if (ret < 0)								\
		return ret;							\
										\
	if (val != 0 && val < min_schedtime_threshold) {			\
		return -EINVAL;							\
	}									\
										\
	task = get_proc_task(file_inode(file));					\
	if (!task)								\
		goto out_no_task;						\
										\
	extra_task = task_to_vendor_task(task);					\
	if (!extra_task)							\
		goto out_no_extra_task;						\
	extra_task->name = val;							\
	if (task->pid == task->tgid) {						\
		for_each_thread(task, thread) {                                 \
			extra_thread = task_to_vendor_task(thread);		\
			extra_thread->name = val;                               \
		}								\
	}									\
out_no_extra_task:								\
	put_task_struct(task);							\
out_no_task:									\
	return count;								\
}										\
										\
static const struct file_operations proc_##name##_operations = {		\
	.read		= proc_##name##_read,					\
	.write		= proc_##name##_write,					\
	.llseek		= generic_file_llseek,					\
};
#endif
#endif

